﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lucene.Net;
using Lucene.Net.Store;
using Lucene.Net.Index;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Search;
using Lucene.Net.QueryParsers;
using Lucene.Net.Analysis;
using System.Configuration;

namespace Dominio
{
    class LuceneIndexador : Indexador
    {

        private String dirIndex = @"c:\LuceneIndice";
            //System.Configuration.ConfigurationSettings.AppSettings["IndexDirectory"];
        private Directory dir;
        

        public LuceneIndexador()
        {
            // Si no existe el dirIndex, crearlo
            Directory directory;
            IndexWriter ix = null;
            try
            {
                if (!Lucene.Net.Index.IndexReader.IndexExists(dirIndex))
                {
                    directory = FSDirectory.GetDirectory(dirIndex, true);
                    // Creo el indice con el indexWriter en true
                    ix = new IndexWriter(directory, new StandardAnalyzer(), true);
                }
                else
                    directory = FSDirectory.GetDirectory(dirIndex, false);

               
                dir = directory;
            }
            finally
            {
                if (ix != null)
                    ix.Close();
            }
        }

        override public void indexarProducto(BLProducto p)
        {
            IndexWriter ixW = null;

            try
            {
                //Creo un analizador para analizar el texto
                Analyzer analyzer = new StandardAnalyzer();

                // Creo un IndexWriter para escribir el indice. Create en false. Si esta en true, sobreescribe el indice.
                ixW = new IndexWriter(dir, analyzer, false);

                //Creo un documento.
                Document doc = new Document();

                // Agrego las celdas a indexar al documento
                doc.Add(new Field(IX_NOMBRE, p.ProdNombre, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));
                doc.Add(new Field(IX_DESCRIPCION, p.ProdDescripcion, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));
                doc.Add(new Field(IX_FABRICANTE, p.ProdFabricante, Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));
                doc.Add(new Field(IX_PRECIO, p.ProdPrecio.ToString(), Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));
                doc.Add(new Field(IX_IDCATEGORIA, p.categoria.CatId.ToString(), Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));
                doc.Add(new Field(IX_IDPRODUCTO, p.ProdId.ToString(), Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));
                doc.Add(new Field(IX_CODIGO, p.ProdCod.ToString(), Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));

                // Agrego el documento al indice
                ixW.AddDocument(doc);

                //Optimizacion y cierre
                ixW.Optimize();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (ixW != null)
                    ixW.Close();
            }
        }

        public override void reindexarProducto(BLProducto p)
        {
            try
            {
                desindexarProducto(p);
                indexarProducto(p);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public override void desindexarProducto(BLProducto p)
        {
            IndexModifier ixM = null;
            try
            {
                ixM = new IndexModifier(dir, new StandardAnalyzer(), false);
                Term term = new Term(IX_IDPRODUCTO, p.ProdId.ToString());
                ixM.DeleteDocuments(term);

            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (ixM != null)
                    ixM.Close();
            }
        }

        public override List<BLProducto> buscar(Dictionary<string, string> busqueda)
        {
            List<BLProducto> listaret = new List<BLProducto>();
            try
            {

                List<string> queryes = new List<string>();
                List<string> fields = new List<string>();
                List<BooleanClause.Occur> booleanclause = new List<BooleanClause.Occur>();

                Dictionary<string,string>.Enumerator it = busqueda.GetEnumerator();
                while (it.MoveNext())
                {

                    queryes.Add(it.Current.Value+"~");
                    fields.Add(it.Current.Key);
                    booleanclause.Add(BooleanClause.Occur.MUST);
                    
                }

                Query query = MultiFieldQueryParser.Parse(queryes.ToArray(), fields.ToArray(), booleanclause.ToArray() , new StandardAnalyzer());
                
                IndexSearcher searcher = new IndexSearcher(dir);

                Hits hits = searcher.Search(query);
                AdministracionHandler adm = AdministracionHandler.getInstance();
                for (int i = 0; i < hits.Length(); i++)
                {
                    Lucene.Net.Documents.Document doc = hits.Doc(i);
                    
                    BLProducto p = adm.getBLProducto(int.Parse(doc.GetField(IX_IDPRODUCTO).StringValue()));
                    listaret.Add(p);
                }

                return listaret;
            }catch(Exception ex)
            {
                throw ex;
            }
        }

        public override List<BLProducto> buscar(string idCategoria, string criterio)
        {
            List<BLProducto> listaret = new List<BLProducto>();
            try
            {
                IndexSearcher searcher = new IndexSearcher(dir);
                criterio = criterio + "*~";
                QueryParser parser = new Lucene.Net.QueryParsers.QueryParser(IX_IDCATEGORIA, new StandardAnalyzer());
                
                Query query = parser.Parse(idCategoria);
                
                Hits hitsCategoria = searcher.Search(query);
                int cantCategoria = hitsCategoria.Length();


                List<string> queryes = new List<string>() {idCategoria, criterio,criterio,criterio,criterio,criterio,criterio};
                List<string> fields = new List<string>() {IX_IDCATEGORIA,IX_DESCRIPCION, IX_FABRICANTE, IX_IDPRODUCTO, IX_NOMBRE, IX_PRECIO,IX_CODIGO };

                Query query2 = MultiFieldQueryParser.Parse(queryes.ToArray(), fields.ToArray(), new StandardAnalyzer());

                Hits hits = searcher.Search(query2);
                AdministracionHandler adm = AdministracionHandler.getInstance();
                if (hits.Length() != cantCategoria)
                for (int i = 0; i < hits.Length(); i++)
                {
                    Lucene.Net.Documents.Document doc = hits.Doc(i);
                    BLProducto p = adm.getBLProducto(int.Parse(doc.GetField(IX_IDPRODUCTO).StringValue()));
                    listaret.Add(p);
                }

                return listaret;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public override List<BLProducto> buscar(string criterio)
        {
            //Creo un indice buscador que realizara la busqueda
            IndexSearcher searcher = new IndexSearcher(dir);
            List<BLProducto> list = new List<BLProducto>();
            criterio = criterio + "*~";
            //QueryParser parser = new Lucene.Net.QueryParsers.QueryParser("Nombre", new StandardAnalyzer());

            List<string> fields = new List<string>() { IX_DESCRIPCION, IX_FABRICANTE, IX_IDCATEGORIA, IX_IDPRODUCTO, IX_NOMBRE, IX_PRECIO };
            List<BooleanClause.Occur> booleanclause = new List<BooleanClause.Occur>() { BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD };

            Query query = MultiFieldQueryParser.Parse(criterio, fields.ToArray(), booleanclause.ToArray(), new StandardAnalyzer());
            //Query query = null;
            //query = parser.Parse(criterio);


            Hits hits = searcher.Search(query);
            AdministracionHandler adm = AdministracionHandler.getInstance();
            for (int i = 0; i < hits.Length(); i++)
            {
                Lucene.Net.Documents.Document doc = hits.Doc(i);
                BLProducto p = adm.getBLProducto(int.Parse(doc.GetField(IX_IDPRODUCTO).StringValue()));
                list.Add(p);
            }

            
            return list;
        }
    }
}
